package org.chipu.jnids.beans;

import java.net.InetSocketAddress;
import java.util.Comparator;
import org.chipu.jnids.Jnids;
import org.chipu.shared.util.singletons.NetworkUtils;
import org.chipu.shared.util.singletons.Utils;

public class Flow {
	public static final Comparator<Flow> startTimeComparator = new Comparator<Flow>() {

		@Override
		public int compare(Flow o1, Flow o2) {
			return (int) Math.signum(o1.startTimeInSeconds - o2.startTimeInSeconds);
		}
	};
	public static final Comparator<Flow> endTimeComparator = new Comparator<Flow>() {

		@Override
		public int compare(Flow o1, Flow o2) {
			return (int) Math.signum(o1.stopTimeInSeconds - o2.stopTimeInSeconds);
		}
	};
	// This is much more efficient than a Date and a duration
	public final int startTimeInSeconds;
	public final int stopTimeInSeconds;
	public final InetSocketAddress orgAddress;
	public final InetSocketAddress destAddress;
	public final byte protocol;

	public Flow(Number protocol, Number startTimestamp, Number duration, String orgIp_dotted, String destIp_dotted,
		Number orgPort, Number destPort) {
		this(protocol.byteValue(), startTimestamp.intValue(), duration.intValue(), orgIp_dotted, destIp_dotted, orgPort
			.intValue(), destPort.intValue());
	}

	public Flow(byte protocol, int startTimestampInSeconds, int duration, String orgIp, String destIp, int orgPort, int destPort) {
		this.protocol = protocol;
		startTimeInSeconds = startTimestampInSeconds;
		stopTimeInSeconds = startTimeInSeconds + duration;
		orgAddress = new InetSocketAddress(orgIp, orgPort);
		destAddress = new InetSocketAddress(destIp, destPort);
	}

	@Override
	public String toString() {
		return "Flow[protocol=" + NetworkUtils.guessProtocolName(protocol) + ", " + getSimpleIp(orgAddress) + "\t-> "
			+ getSimpleIp(destAddress) + ", at " + Utils.toDate(startTimeInSeconds) + "-" + Utils.toDate(stopTimeInSeconds) + "]";
	}

	private static String getSimpleIp(InetSocketAddress address) {
		String s = address.toString();
		if (s.charAt(0) == '/')
			s = s.substring(1);
		return s.substring(0, s.indexOf(':') + 1) + getPortName(Integer.parseInt(s.substring(s.indexOf(':') + 1)));
	}

	private static String getPortName(int port) {
		String name = NetworkUtils.getPortName(port);
		return String.valueOf(port) + (name == null? "": "(" + name + ")");
	}

	@Override
	public boolean equals(Object obj) {
		if (obj == this)
			return true;
		if (!(obj instanceof Flow))
			return false;
		Flow o = (Flow) obj;
		return startTimeInSeconds == o.startTimeInSeconds && stopTimeInSeconds == o.stopTimeInSeconds
			&& orgAddress.equals(o.orgAddress) && destAddress.equals(o.destAddress);
	}

	@Override
	public int hashCode() {
		int hash = 5;
		hash = 23 * hash + startTimeInSeconds;
		hash = 23 * hash + stopTimeInSeconds;
		hash = 23 * hash + (orgAddress != null? orgAddress.hashCode(): 0);
		hash = 23 * hash + (destAddress != null? destAddress.hashCode(): 0);
		hash = 23 * hash + protocol;
		return hash;
	}

	public boolean isFromInside() {
		return Jnids.belongsToInternalNetwork(orgAddress.getAddress());
	}

	public boolean isToInside() {
		return Jnids.belongsToInternalNetwork(destAddress.getAddress());
	}

	// PERFORMANCE (40% of profile creation)
	public boolean wasActivedAt(int timeInSeconds) {
		return startTimeInSeconds < timeInSeconds && stopTimeInSeconds > timeInSeconds;
	}
}